%{
#include <string>
#include "Scanner.h"


const std::string flexDebugMessageBeginning = "<FLEX DEBUG>: " ;

void flexDebugMessage(const std::string& msg)
{
		std::cout<<flexDebugMessageBeginning<<msg << std::endl;	
}


/* import the parser's token type into a local typedef */
typedef MathematicaTranslator::Parser::token token;
typedef MathematicaTranslator::Parser::token_type token_type;

/* By default yylex returns int, we use token_type. Unfortunately yyterminate
 * by default returns 0, which is not of token_type. */
#define yyterminate() return token::END

#define TOKEN(t) (yylval->token = t)
#define SAVE_TOKEN yylval->string = new std::string(yytext, yyleng)

%}

%option C++ noyywrap yyclass="Scanner" nodefault
%option batch

/*disable in release version*/
%option debug

/* enables the use of start condition stacks */
%option stack

%option prefix="MathematicaTranslator"

%option nounput

%{

#define YY_USER_ACTION  yylloc->columns(yyleng);

%}

LINE_TERMINATOR  \r|\n|\r\n
INPUT_CHARACTER  [^\r\n]
LETTER			[a-zA-Z]
DIGIT			[0-9]

WHITESPACE		{LINE_TERMINATOR}|[ \t\f]+

/* comments */
COMMENT			{TRADITIONAL_COMMENT}|{ENDOFLINE_COMMENT} 

TRADITIONAL_COMMENT	"/*"[^*]~"*/"|"/*""*"+"/"
ENDOFLINE_COMMENT	"//"{INPUT_CHARACTER}*{LINE_TERMINATOR}?

IDENTIFIER		{LETTER}({LETTER}|{DIGIT})*

/* integer literals */
DECINTEGER_LITERAL	0|[1-9]{DIGIT}*
DECLONG_LITERAL		{DECINTEGER_LITERAL}[lL]

HEXINTEGER_LITERAL	0[xX]0*{HEXDIGIT}{1,8}
HEXLONG_LITERAL		0[xX]0*{HEXDIGIT}{1,16}[lL]
HEXDIGIT			[0-9a-fA-F]

OCTINTEGER_LITERAL	0+[1-3]?{OCTDIGIT}{1,15}
OCTLONG_LITERAL		0+1?{OCTDIGIT}{1,21}[lL]
OCTDIGIT			[0-7]

/* floating point literals */        
FLOAT_LITERAL		({FLIT1}|{FLIT2}|{FLIT3}){EXPONENT}?[fF]
DOUBLE_LITERAL		({FLIT1}|{FLIT2}|{FLIT3}){EXPONENT}?

FLIT1		[0-9]+\.[0-9]* 
FLIT2		\.[0-9]+ 
FLIT3		[0-9]+ 
EXPONENT	[eE][+-]?[0-9]+

/* string and character literals */
STRING_CHARACTER		[^\r\n\"\\]
SINGLE_CHARACTER		[^\r\n\'\\]

%%

%{
	yylloc->step();
%}

"Null" |
"Abs" |
"AddTo" |
"And" |
"Apart" |
"Append" |
"Apply" |
"ArcCos" |
"ArcSin" |
"ArcTan" |
"Arg" |
"Array" |
"AtomQ" |
"Binomial" |
"Blank" |
"Block" |
"Break" |
"CartesianProduct" |
"Cases" |
"Catalan" |
"CatalanNumber" |
"Ceiling" |
"CharacteristicPolynomial" |
"ChessboardDistance" |
"Chop" |
"Clear" |
"ClearAll" |
"Complement" |
"Complex" |
"ComplexInfinity" |
"ComposeList" |
"CompoundExpression" |
"Condition" |
"Conjugate" |
"ConstantArray" |
"Continue" |
"ContinuedFraction" |
"CoprimeQ" |
"Cos" |
"Cosh" |
"Cot" |
"Cross" |
"Csc" |
"Curl" |
"D" |
"Decrement" |
"Default" |
"Definition" |
"Degree" |
"Denominator" |
"Depth" |
"Det" |
"DiagonalMatrix" |
"DigitQ" |
"Dimensions" |
"Divergence" |
"DivideBy" |
"Dot" |
"Drop" |
"E" |
"Eigenvalues" |
"Eigenvectors" |
"Equal" |
"Erf" |
"EuclidianDistance" |
"EulerGamma" |
"EulerPhi" |
"EvenQ" |
"Exp" |
"Expand" |
"ExpandAll" |
"ExtendedGCD" |
"Extract" |
"Factor" |
"Factorial" |
"Factorial2" |
"FactorInteger" |
"FactorSquareFree" |
"FactorTerms" |
"False" |
"Fibonacci" |
"FindRoot" |
"First" |
"Fit" |
"FixedPoint" |
"Floor" |
"Fold" |
"FoldList" |
"For" |
"FreeQ" |
"FromCharacterCode" |
"FromContinuedFraction" |
"FullForm" |
"Function" |
"Gamma" |
"GCD" |
"Glaisher" |
"GoldenRatio" |
"Greater" |
"GreaterEqual" |
"GroebnerBasis" |
"HarmonicNumber" |
"Head" |
"HilbertMatrix" |
"Hold" |
"Horner" |
"I" |
"IdentityMatrix" |
"If" |
"Im" |
"Increment" |
"Infinity" |
"Inner" |
"IntegerPartitions" |
"IntegerQ" |
"Integrate" |
"Intersection" |
"Inverse" |
"JacobiMatrix" |
"JacobiSymbol" |
"JavaForm" |
"Join" |
"Khinchin" |
"KOrderlessPartitions" |
"KPartitions" |
"Last" |
"LCM" |
"LeafCount" |
"Length" |
"Less" |
"LessEqual" |
"LetterQ" |
"Level" |
"Limit" |
"LinearProgramming" |
"LinearSolve" |
"Log" |
"LowerCaseQ" |
"LUDecomposition" |
"ManhattanDistance" |
"Map" |
"MapAll" |
"MapThread" |
"MatchQ" |
"MatrixPower" |
"MatrixQ" |
"Max" |
"Mean" |
"Median" |
"MemberQ" |
"Min" |
"Mod" |
"Module" |
"MoebiusMu" |
"Most" |
"Multinomial" |
"N" |
"Negative" |
"Nest" |
"NestList" |
"NextPrime" |
"NIntegrate" |
"NonCommutativeMultiply" |
"NonNegative" |
"Norm" |
"Not" |
"NRoots" |
"NumberQ" |
"Numerator" |
"NumericQ" |
"OddQ" |
"Or" |
"Order" |
"OrderedQ" |
"Out" |
"Outer" |
"Package" |
"ParametricPlot" |
"Part" |
"Partition" |
"Pattern" |
"Permutations" |
"Pi" |
"Plot" |
"Plot3D" |
"Plus" |
"PolynomialExtendedGCD" |
"PolynomialGCD" |
"PolynomialLCM" |
"PolynomialQ" |
"PolynomialQuotient" |
"PolynomialQuotientRemainder" |
"PolynomialRemainder" |
"Position" |
"Positive" |
"PossibleZeroQ" |
"Power" |
"PowerExpand" |
"PowerMod" |
"PreDecrement" |
"PreIncrement" |
"Prepend" |
"PrimeQ" |
"PrimitiveRoots" |
"Print" |
"Product" |
"Quotient" |
"RandomInteger" |
"RandomReal" |
"Range" |
"Rational" |
"Rationalize" |
"Re" |
"ReplaceAll" |
"ReplaceRepeated" |
"Rest" |
"Return" |
"Reverse" |
"RootIntervals" |
"Roots" |
"RotateLeft" |
"RotateRight" |
"Rule" |
"RuleDelayed" |
"SameQ" |
"Sec" |
"Select" |
"Set" |
"SetAttributes" |
"SetDelayed" |
"Sign" |
"SignCmp" |
"Simplify" |
"Sin" |
"SingularValueDecomposition" |
"Sinh" |
"Solve" |
"Sort" |
"Sqrt" |
"SquaredEuclidianDistance" |
"SquareFreeQ" |
"StringDrop" |
"StringJoin" |
"StringLength" |
"StringTake" |
"Subsets" |
"SubtractFrom" |
"Sum" |
"SyntaxLength" |
"SyntaxQ" |
"Table" |
"Take" |
"Tan" |
"Tanh" |
"Taylor" |
"Thread" |
"Through" |
"Times" |
"TimesBy" |
"Timing" |
"ToCharacterCode" |
"Together" |
"ToString" |
"Total" |
"ToUnicode" |
"Tr" |
"Trace" |
"Transpose" |
"TrigReduce" |
"TrigToExp" |
"True" |
"TrueQ" |
"Trunc" |
"Unequal" |
"Union" |
"UnsameQ" |
"UpperCaseQ" |
"ValueQ" |
"VandermondeMatrix" |
"Variables" |
"VectorQ" |
"While"					{ 
							#ifdef DEBUG
								flexDebugMessage("KEYWORD TOKEN");
							#endif
							return static_cast<token_type> (*yytext);
						}
{WHITESPACE}			{
							/**/
						}
":="					{
							#ifdef DEBUG
								flexDebugMessage("ASSIGN TOKEN");
							#endif
							return token::ASSIGN;
						}
"+"						{
							#ifdef DEBUG
								flexDebugMessage("ADD TOKEN");
							#endif
							SAVE_TOKEN;
							return token::ADD;
						}
"*"						{
							#ifdef DEBUG
								flexDebugMessage("MUL TOKEN");
							#endif
							SAVE_TOKEN;
							return token::MUL;
						}
"/"						{
							#ifdef DEBUG
								flexDebugMessage("DIV TOKEN");
							#endif
							SAVE_TOKEN;
							return token::DIV;
						}
"-"						{
							#ifdef DEBUG
								flexDebugMessage("SUB TOKEN");
							#endif
							SAVE_TOKEN;
							return token::SUB;
						}
"."						{
							#ifdef DEBUG
								flexDebugMessage("DOT TOKEN");
							#endif
							SAVE_TOKEN;
							return token::DOT;
						}
"="						{
							#ifdef DEBUG
								flexDebugMessage("EQ TOKEN");
							#endif
							return token::EQ;
						}
"{"						{
							#ifdef DEBUG
								flexDebugMessage("BRACEOPEN TOKEN");
							#endif
							return token::BRACEOPEN;
						}
"}"						{
							#ifdef DEBUG
								flexDebugMessage("BRACECLOSE TOKEN");
							#endif
							return token::BRACECLOSE;
						}
"("						{
							#ifdef DEBUG
								flexDebugMessage("PARENOPEN TOKEN");
							#endif
							return token::PARENOPEN;
						}
")"						{
							#ifdef DEBUG
								flexDebugMessage("PARENCLOSE TOKEN");
							#endif
							return token::PARENCLOSE;
						}
"["						{
							#ifdef DEBUG
								flexDebugMessage("BRACKETOPEN TOKEN");
							#endif
							return token::BRACKETOPEN;
						}
"]"						{
							#ifdef DEBUG
								flexDebugMessage("BRACKETCLOSE TOKEN");
							#endif
							return token::BRACKETCLOSE;
						}
"++"					{
							#ifdef DEBUG
								flexDebugMessage("INC TOKEN");
							#endif
							SAVE_TOKEN;
							return token::INC;
						}
"--"					{
							#ifdef DEBUG
								flexDebugMessage("DEC TOKEN");
							#endif
							SAVE_TOKEN;
							return token::DEC;
						}
"||"					{
							#ifdef DEBUG
								flexDebugMessage("OR TOKEN");
							#endif
							SAVE_TOKEN;
							return token::OR;
						}
"&&"					{
							#ifdef DEBUG
								flexDebugMessage("AND TOKEN");
							#endif
							SAVE_TOKEN;
							return token::AND;
						}
"=="					{
							#ifdef DEBUG
								flexDebugMessage("ISEQUAL TOKEN");
							#endif
							SAVE_TOKEN;
							return token::ISEQUAL;
						}
"!="					{
							#ifdef DEBUG
								flexDebugMessage("ISNOTEQUAL TOKEN");
							#endif
							SAVE_TOKEN;
							return token::ISNOTEQUAL;
						}	
">="					{
							#ifdef DEBUG
								flexDebugMessage("GRATEROREQUAL TOKEN");
							#endif
							SAVE_TOKEN;
							return token::GE;
						}
"<="					{
							#ifdef DEBUG
								flexDebugMessage("LESSOREQUAL TOKEN");
							#endif
							SAVE_TOKEN;
							return token::LE;
						}
">"						{
							#ifdef DEBUG
								flexDebugMessage("GREATER TOKEN");
							#endif
							SAVE_TOKEN;
							return token::GT;
						}	
"<"						{
							#ifdef DEBUG
								flexDebugMessage("SMALLER TOKEN");
							#endif
							SAVE_TOKEN;
							return token::LT;
						}
{DECINTEGER_LITERAL} |
{DECLONG_LITERAL}		{
							#ifdef DEBUG
								flexDebugMessage( std::string("DECINTEGER TOKEN: ") + yytext);
							#endif
							SAVE_TOKEN;
							return token::DECINTEGER;
						}
{HEXINTEGER_LITERAL} |
{HEXLONG_LITERAL}		{
							#ifdef DEBUG
								flexDebugMessage( std::string("HEXINTEGER TOKEN: ") + yytext);
							#endif
							SAVE_TOKEN;
							return token::HEXINTEGER;
						}
{OCTINTEGER_LITERAL} | 
{OCTLONG_LITERAL}		{
							#ifdef DEBUG
								flexDebugMessage( std::string("OCTINTEGER TOKEN: ") + yytext);
							#endif
							SAVE_TOKEN;
							return token::OCTINTEGER;
						}
{FLOAT_LITERAL}			{
							#ifdef DEBUG
								flexDebugMessage(std::string("FLOATNUMBER TOKEN: ") + yytext);
							#endif
							SAVE_TOKEN;
							return token::FLOATNUMBER;
						}
{DOUBLE_LITERAL}		{
							#ifdef DEBUG
								flexDebugMessage(std::string("DOUBLENUMBER TOKEN: ") + yytext);
							#endif
							SAVE_TOKEN;
							return token::DOUBLENUMBER;
						}
{IDENTIFIER}			{
							#ifdef DEBUG
								flexDebugMessage(std::string("ID TOKEN: ") + yytext);
							#endif
							SAVE_TOKEN;
							return token::ID;
						}
\n						{
							/**/
						}
.						{	
							#ifdef DEBUG
								flexDebugMessage(std::string("UNKNOWN CHARACTER: ") + yytext);
							#endif
							//pass all unknown commands, tokens back to bison
							return static_cast<token_type> (*yytext);
						}

%% /* Additional code */

namespace MathematicaTranslator
{
	Scanner::Scanner(std::istream* in,
					 std::ostream* out)
    : MathematicaTranslatorFlexLexer(in, out)
	{
	}
	Scanner::~Scanner()
	{
	}

	void Scanner::set_debug(bool b)
	{
		yy_flex_debug = b;
	}

}
